﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;

namespace H2O
{
    public class AsyncRequestState
    {

        const int BUFFER_SIZE = 1024;
        public StringBuilder requestData;
        public byte[] BufferRead;
        public HttpWebRequest request;
        public HttpWebResponse response;
        public Stream streamResponse;
        public AsyncRequestState()
        {
            BufferRead = new byte[BUFFER_SIZE];
            requestData = new StringBuilder("");
            request = null;
            streamResponse = null;
        }
    }

    class AsyncWebRequest
    {
        public ManualResetEvent allDone = new ManualResetEvent(false);
        const int BUFFER_SIZE = 1024;
        const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout
        public delegate void GetDataHandle(string html);
        // public event GetDataHandle GetDataEvent;

        // Abort the request if the timer fires.
        private void TimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                HttpWebRequest request = state as HttpWebRequest;
                if (request != null)
                {
                    request.Abort();
                }
            }
        }

        public string send(string url)
        {
            try
            {
                // Create a HttpWebrequest object to the desired URL. 
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Timeout = DefaultTimeout;
                webRequest.ReadWriteTimeout = DefaultTimeout;
                webRequest.Method = "GET";
                webRequest.ContentType = "application/x-www-form-urlencoded";

                webRequest.UserAgent = "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; Alexa Toolbar)";
                webRequest.Headers.Add("accept-language", "zh-cn");
                webRequest.Headers.Add("accept-encoding", "gzip,   deflate");

                // Create an instance of the RequestState and assign the previous myHttpWebRequest
                // object to its request field.  
                AsyncRequestState myRequestState = new AsyncRequestState();
                myRequestState.request = webRequest;


                // Start the asynchronous request.
                IAsyncResult result =
                  (IAsyncResult)webRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);

                // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
                ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback),
                        webRequest, DefaultTimeout, true);

                // The response came in the allowed time. The work processing will happen in the 
                // callback function.
                allDone.WaitOne();

                // Release the HttpWebResponse resource.
                if (myRequestState.response != null)
                {
                    webRequest.Abort(); 
                    myRequestState.response.Close();
                } 

                return myRequestState.requestData.ToString();
            }
            catch (WebException e)
            {
                return "";// e.ToString();
            }
            catch (Exception e)
            {
                return ""; //e.ToString();
            }
        }

        private void RespCallback(IAsyncResult asynchronousResult)
        {
            AsyncRequestState myRequestState = null;
            try
            {
                // State of request is asynchronous.
                myRequestState = (AsyncRequestState)asynchronousResult.AsyncState;
                HttpWebRequest myHttpWebRequest = myRequestState.request;
                myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);

                // Read the response into a Stream object.
                Stream responseStream = myRequestState.response.GetResponseStream();
                myRequestState.streamResponse = responseStream;

                // Begin the Reading of the contents of the HTML page and print it to the console.
                IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0,
                    BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                return;
            }
            catch (WebException e)
            {
                //myRequestState.requestData.Append(e.ToString());
                allDone.Set();
            }

        }
        private void ReadCallBack(IAsyncResult asyncResult)
        {
            AsyncRequestState myRequestState = null;
            try
            {

                myRequestState = (AsyncRequestState)asyncResult.AsyncState;
                Stream responseStream = myRequestState.streamResponse;
                int read = responseStream.EndRead(asyncResult);

                if (read > 0)
                {
                    myRequestState.requestData.Append(Encoding.UTF8.GetString(myRequestState.BufferRead, 0, read));
                    IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                    return;
                }
                else
                {
                    if (myRequestState.requestData.Length > 1)
                    {
                        allDone.Set();
                    }
                    responseStream.Close();
                }

            }
            catch (WebException e)
            {
                //myRequestState.requestData.Append(e.ToString());
                allDone.Set();
            }


        }
    }

}
